home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Franz PD
/
Franz PD Disk #324 (1994-04)(Rhein-Sieg-Soft).zip
/
Franz PD Disk #324 (1994-04)(Rhein-Sieg-Soft).adf
/
VideoText3.5
/
source
/
s_i2cbusIO.s
< prev
next >
Wrap
Text File
|
1994-04-01
|
5KB
|
181 lines
;=============================================================================
; s_i2cbusIO.s: Assembler-Version der KICK-Pascal Prozedur i2cbusIO (seriell)
; Parameterübergabe (auf dem Stack):
; 12(A7).B: logische Busadresse -> D0
; 8(A7).L: Zeiger auf den I/O-Puffer -> A0
; 6(A7).W: Anzahl zu übertragender Daten -> D1
; 4(A7).W: Zeitschleifen-Durchgänge -> D5
; Rückgabewert:
; D0.W: Status, 0 = OK, 1 = Fehler, 2 = Fehler beim Adressbyte
;-----------------------------------------------------------------------------
; Funktionsweise:
; Startet den I²C-Bus und spricht den in D0 bezeichneten Chip an. Wenn D1
; negativ ist, werden -D1 Bytes vom Bus geholt und ab Adresse A0 im Speicher
; abgelegt, sonst +D1 Bytes ab A0 über den Bus abgeschickt. Die Busadresse
; (D0) wird dabei automatisch zur Schreib- bzw. Leseadresse gemäß I²C-Bus-
; Konvention korrigiert. Abschließend wird der I²C-Bus wieder gestoppt.
; Anmerkungen:
; 1. Die über D5 bestimmte Zeitschleife soll den Bustakt bremsen, wobei
; maximal 100 kHz zulässig sind, "zu langsam" gibt es dagegen am I²C-Bus
; NICHT. Auf normalen Amigas sollte D5=0 sein.
; 2. Mehr Bytes zum Lesen anzufordern, als der bereitgestellte Puffer fassen
; kann, ist ein Fehler, der nicht erkannt werden kann und wahrscheinlich
; mit einem GURU endet.
;=============================================================================
; interne Registerverwendung:
; D0: Datenbyte, das gesendet oder empfangen wird
; D1: Anzahl zu übertragende Bytes
; D2: Zähler über gesendete Bytes
; D3: Zähler über 8 Bits
; D4: Zähler für Zeitschleife
; D5: Grenze für Zeitschleife
; A0: Pufferzeiger
; A1: Adresse des CIA-Ports
CIABPRA = $BFD000
CIABDDRA = $BFD200
ClkOutBit = 6 ; CIAB_COMRTS
ClkInBit = 4 ; CIAB_COMCTS
DataOutBit = 7 ; CIAB_COMDTR
DataInBit = 5 ; CIAB_COMCD
DELAY MACRO
move.w d5,d4
loop\@ dbf d4,loop\@
ENDM
; Linker-Information:
xdef s_i2cbusIO
s_i2cbusIO:
; Parameter vom Stack holen:
move.b 12(a7),d0
move.l 8(a7),a0
move.w 6(a7),d1
move.w 4(a7),a1
test:
; veränderte Register retten: D2,D3,D4,D5
movem.l d2-d5,-(a7)
; einen der Parameter noch ins richtige Register packen:
move.w a1,d5
; CIA-Datenrichtungsregister initialisieren
move.l #CIABDDRA,a1
bset #ClkOutBit,(a1)
bset #DataOutBit,(a1)
bclr #ClkInBit,(a1)
bclr #DataInBit,(a1)
; Bus in Ruhezustand bringen: DATA=HI, CLK=HI
move.l #CIABPRA,a1
bset #DataOutBit,(a1)
bset #ClkOutBit,(a1)
; Bus starten (Protokollverletzung H->L): DATA=LO, CLK=LO
DELAY
bclr #DataOutBit,(a1)
DELAY
bclr #ClkOutBit,(a1)
DELAY
; Soll ich senden oder empfangen?
bclr #0,d0 ; Voreinstellung: Adresse als Sendeadresse
tst.w d1
bpl .zweck
bset #0,d0 ; Adresse als Leseadresse
.zweck:
; Daten senden, mindestens die Adresse, und evtl. <D1> weitere Bytes
; (Adressbyte steht bereits in D0):
clr.w d2 ; Bytezähler auf Null
SendLoop: ; das in D0 enthaltene Byte über den Bus schicken, MSB zuerst
moveq.b #7,d3
SBitLoop:
btst d3,d0
beq .SL1
bset #DataOutBit,(a1) ; "1" senden
bra .SL2
.SL1 bclr #DataOutBit,(a1) ; "0" senden
.SL2: ; Einen CLK-Impuls geben, um das Bit lesen zu lassen
bset #ClkOutBit,(a1)
DELAY
bclr #ClkOutBit,(a1)
DELAY
dbf d3,SBitLoop
; 9. CLK-Impuls, um Quittungsbit zu lesen:
bset #DataOutBit,(a1) ; sonst liest man nur das eigene LO!
bset #ClkOutBit,(a1)
DELAY
btst #DataInBit,(a1)
bne SendErr ; DATA=HI -> NAK, Übertragung abbrechen
bclr #ClkOutBit,(a1)
DELAY
; genug Daten gesendet?
addq.w #1,d2 ; gesendetes Byte zählen
cmp.w d1,d2 ; dran denken: Adressbyte wurde mitgezählt
bgt SendEnd ; ja, fertig (schließt auch den Fall d1<0 ein)
move.b (a0)+,d0 ; nein, Byte aus Puffer holen
bra SendLoop
SendErr:
moveq.w #1,d0 ; Status = unquittiertes Byte
tst.w d2 ; das wievielte Byte war es?
bne BusStop ; irgendeins
moveq.w #2,d0 ; sonst: Status = unquittiertes Adressbyte
bra BusStop
SendEnd:
tst.w d1
bmi RecvLoop ; es sollen auch noch Bytes empfangen werden
moveq.w #0,d0 ; Status = OK
bra BusStop
; soviele Bytes empfangen, wie in A1 angegeben:
RecvLoop: ; ein Byte vom Bus holen, MSB zuerst, und in D0 zusammensetzen
bset #DataOutBit,(a1) ; DATA-Leitung freigeben
clr.b d0
moveq.b #7,d3
RBitLoop:
; Einen CLK-Impuls geben, ein Bit lesen:
bset #ClkOutBit,(a1)
DELAY
btst #DataInBit,(a1)
beq .RL1 ; "0" empfangen, nichts tun
bset d3,d0 ; "1" empfangen, entsprechendes Bit setzen
.RL1 bclr #ClkOutBit,(a1)
DELAY
dbf d3,RBitLoop
move.b d0,(a0)+ ; Byte im Puffer speichern
; Quittierungsbit senden, "0", außer nach dem letzten Byte:
addq.w #1,d1 ; empfangenes Byte zählen
beq .RL2 ; letztes Byte, DATA auf HI lassen
bclr #DataOutBit,(a1) ; nein, DATA=LO
.RL2: ; CLK-Impuls geben, Quittungsbit lesen lassen:
bset #ClkOutBit,(a1)
DELAY
bclr #ClkOutBit,(a1)
DELAY
; alle Daten empfangen?
tst.w d1
bne RecvLoop ; nein, weitermachen
moveq.w #0,d0 ; Status: OK
BusStop: ; I²C-Bus stoppen (Protokollverletzung L->H): CLK=HI, DATA=HI
; zunächst noch CLK=LO, DATA=LO sicherstellen:
bclr #ClkOutBit,(a1)
bclr #DataOutBit,(a1)
DELAY
bset #ClkOutBit,(a1)
DELAY
bset #DataOutBit,(a1)
DELAY
; gerettete Register zurückholen: D2,D3,D4,D5
movem.l (a7)+,d2-d5
rts
end